package com.netwit.web.filter;

import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.LinkedHashMap;

@WebFilter(filterName = "StaticCacheFilter", urlPatterns = "/*")
public class StaticFileCachedFilter implements Filter {
    private Logger log = LoggerFactory.getLogger(StaticFileCachedFilter.class);

    @Autowired
    ServletContext context;

    @Value("${onez.static.cache.mode:dev}")
    private String cacheMode="dev";

    @Value("${onez.static.cache.filetype:js,css}")
    private String cacheFileType ="js,css";

    private LinkedHashMap<String, String> fileMD5Values;

    @Override
    public void init(FilterConfig filterConfig) {
        fileMD5Values = new LinkedHashMap<>();
        log.info("Static cache filter init.....");
        log.info("cache mode is " + cacheMode + ", cached file type is " + cacheFileType);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse res = (HttpServletResponse)response;

        String uri = req.getRequestURI();
        String ver = req.getParameter("onev");
        String ext = uri.substring(uri.lastIndexOf(".") + 1);
        if (cacheFileType.contains(ext) && StringUtils.isEmpty(ver)) {
            String qry = req.getQueryString();
            if (cacheMode.equalsIgnoreCase("product")) {
                log.debug("cache mode is product.");
                ver = "onev=" + getMD5(req);
            } else {
                log.debug("cache mode is dev.");
                ver = "onev=" + DigestUtils.md5Hex(new FileInputStream(getRealPath(req)));
            }
            res.sendRedirect(uri + "?" + (StringUtils.isEmpty(qry) ? "" : qry + "&") + ver);
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        log.info("Static cache filter destroy.");
    }

    private String getRealPath(HttpServletRequest request) {
        String uri  = request.getRequestURI();
        String ctxpath = request.getContextPath();
        try {
            String clzpath = ResourceUtils.getURL("classpath:").getPath();
            clzpath += uri.replaceFirst(ctxpath, "static");
            // log.info("Path is " + clzpath);
            return clzpath;
        } catch (FileNotFoundException e) {
            log.error(e.getMessage());
        }

        return "";
    }

    private String getMD5(HttpServletRequest request) throws IOException {
        String uri = request.getRequestURI();
        if (fileMD5Values.containsKey(uri)) {
            log.debug("get md5 value from cached: " + uri + " - " + fileMD5Values.get(uri));
            return fileMD5Values.get(uri);
        } else {
            String md5Val = DigestUtils.md5Hex(new FileInputStream(getRealPath(request)));
            log.debug("get md5 value from file: " + uri + " - " +  md5Val);
            if (!StringUtils.isEmpty(md5Val)) fileMD5Values.put(uri, md5Val);
            return md5Val;
        }
    }
}
